package edu.whu.rose.clock.ssql.graphindex;

import java.io.UnsupportedEncodingException;
import java.util.Date;
import java.util.HashSet;
import java.util.Iterator;
import java.util.LinkedHashMap;

import com.sleepycat.je.DatabaseEntry;
import com.sleepycat.je.DatabaseException;

import edu.whu.rose.clock.ssql.binding.NewGraphIndexItemBinding;

public class NewGraphIndexCache {

	private LinkedHashMap<String, NewGraphIndexItem> cache;
	private long capacity;
	private long size;
	private GraphIndexDB gidb;
	private HashSet<String> stored;
	
	private long visit;
	private long hit;
	
	public NewGraphIndexCache(GraphIndexDB gidb, int capacity) {
		cache = new LinkedHashMap<String, NewGraphIndexItem>();
		this.gidb = gidb;
		this.capacity = capacity;
		this.stored = new HashSet<String>();
	}
	
	public void insert(String key, int[] subgraphs, int vertex) throws UnsupportedEncodingException, DatabaseException {
		String lcKey = key.toLowerCase();
		
		NewGraphIndexItem data = cache.get(lcKey);
		if (data != null) {
			data.add(subgraphs, vertex);
			visit++;
			hit++;
		}
		else {
			if (cache.size() == capacity) {
				Iterator<String> it = cache.keySet().iterator();
				if (it.hasNext()) {
					String s = it.next();
					remove(s);
				}
			}
			
			if (stored.contains(lcKey)) {
				data = getFromDB(lcKey);
				stored.remove(lcKey);
				if (data != null) {
					data.add(subgraphs, vertex);
					cache.put(lcKey, data);
					visit++;
				}
				else {
					System.err.println("Error");
				}
			}
			else {
				data = new NewGraphIndexItem();
				data.add(subgraphs, vertex);
				cache.put(lcKey, data);
			}
		}
	}
	
	private void remove(String keyword) throws UnsupportedEncodingException, DatabaseException {
		NewGraphIndexItem gii = cache.remove(keyword);
		putIntoDB(keyword, gii);
		stored.add(keyword);
	}
	
	public void putIntoDB(String key, NewGraphIndexItem data) throws UnsupportedEncodingException, DatabaseException {
		DatabaseEntry keyword = new DatabaseEntry(key.getBytes("UTF-8"));
		DatabaseEntry list = new DatabaseEntry();
		NewGraphIndexItemBinding giib = new NewGraphIndexItemBinding();
		giib.objectToEntry(data, list);
		
		gidb.put(keyword, list);
	}
	
	public NewGraphIndexItem getFromDB(String key) throws UnsupportedEncodingException, DatabaseException {
		NewGraphIndexItem result = gidb.newSearch(key);
		return result;
	}
	
	public void flush() throws UnsupportedEncodingException, DatabaseException {
		Iterator<String> it = cache.keySet().iterator();
		int counter = 0;
		Date stime = new Date();
		Date etime = null;
		while (it.hasNext()) {
			String key = it.next();
			if (key.equals("database")) {
				System.out.println();
			}
			NewGraphIndexItem data = cache.get(key);
			this.putIntoDB(key, data);
			counter++;
			if (counter % 100 == 0) {
				etime = new Date();
				System.out.println(counter + "........................." + (etime.getTime() - stime.getTime()) + "ms");
				stime = etime;
			}
		}
	}
	
	public void statistic() {
		System.out.println("Cache Hit Rate: " + (100 * (double)hit / ((double)visit)) + "%");
	}
	
}
